#include "CAnimals.h"
#include <stdio.h>

CAnimalsFactory AnimalsFactory;

CAnimalRoot AnimalRoot;


//////////////////////////////////////////////////////////////////
//  CAnimals
//////////////////////////////////////////////////////////////////

CAnimals::CAnimals() : m_nCnt(0), m_lpName(nullptr)
{
    AnimalsFactory.LockServer(TRUE);
}

CAnimals::~CAnimals()
{
    AnimalsFactory.LockServer(FALSE);
}

HRESULT __stdcall CAnimals::SetName(IN LPOLESTR lpName)
{
    if (!lpName) return S_FALSE;

    size_t stLen;

    if (m_lpName)
    {
        delete[] m_lpName;
        m_lpName = nullptr;
    }

    stLen = _tcslen(lpName) + sizeof(TCHAR);
    m_lpName = new TCHAR[stLen];
    if (m_lpName)
    {
        RtlZeroMemory(m_lpName, stLen * sizeof(TCHAR));
        RtlCopyMemory(m_lpName, lpName, stLen * sizeof(TCHAR));
    }

    if (m_lpName)
        return S_OK;
    else
        return S_FALSE;
}

HRESULT __stdcall CAnimals::Woof(IN const unsigned char* lpString)
{
    if (m_lpName)
        _tprintf(m_lpName);
    else
        printf("Dog");

    printf(": ");

    if (lpString)
    {
        printf((char*)lpString);
    }
    return S_OK;
}

HRESULT __stdcall CAnimals::Meow(IN const unsigned char* lpString)
{
    if (m_lpName)
        _tprintf(m_lpName);
    else
        printf("Cat");

    printf(": ");

    if (lpString)
    {
        printf((char*)lpString);
    }
    return S_OK;
}

HRESULT __stdcall CAnimals::Oink(IN const unsigned char* lpString)
{
    if (m_lpName)
        _tprintf(m_lpName);
    else
        printf("Pig");

    printf(": ");

    if (lpString)
    {
        printf((char*)lpString);
    }
    return S_OK;
}


//////////////////////////////////////////////////////////////////
//  CAnimalsFactory
//////////////////////////////////////////////////////////////////

CAnimalsFactory::CAnimalsFactory()
{
}

CAnimalsFactory::~CAnimalsFactory()
{
}

HRESULT __stdcall CAnimalsFactory::QueryInterface(REFIID riid, void** ppvObject)
{
    if (!ppvObject)
        return E_POINTER;

    *ppvObject = nullptr;

    if (IID_IClassFactory == riid)
    {
        AddRef();
        *ppvObject = dynamic_cast<IClassFactory*>(this);
    }
    //else if (IID_IOleItemContainer == riid)
    //{
    //    AddRef();
    //    *ppvObject = dynamic_cast<IOleItemContainer*>(this);
    //}
    //else if (IID_IParseDisplayName == riid)
    //{
    //    AddRef();
    //    *ppvObject = dynamic_cast<IParseDisplayName*>(this);
    //}
    else if (IID_IUnknown == riid)
    {
        AddRef();
        *ppvObject = this;
    }
    else
    {
        CAnimals* lpAnimals = new CAnimals;
        return lpAnimals->QueryInterface(riid, ppvObject);
    }

    if (*ppvObject == nullptr)
        return S_FALSE;

    return S_OK;
}

ULONG __stdcall CAnimalsFactory::AddRef()
{
    return 1;
}

ULONG __stdcall CAnimalsFactory::Release()
{
    return 0;
}

HRESULT __stdcall CAnimalsFactory::CreateInstance(IN OPTIONAL IUnknown* pUnkOuter, IN REFIID riid, OUT void** ppvObject)
{
    CAnimals* lpAnimals = new CAnimals;
    return lpAnimals->QueryInterface(riid, ppvObject);
}

HRESULT __stdcall CAnimalsFactory::LockServer(IN BOOL fLock)
{
    if (fLock)
    {
        InterlockedIncrement(&m_nLockTick);
    }
    else
    {
        if (m_nLockTick > 0)
            InterlockedDecrement(&m_nLockTick);
    }

    return S_OK;
}


//////////////////////////////////////////////////////////////////
//  CAnimalRoot
//////////////////////////////////////////////////////////////////

CAnimalRoot::CAnimalRoot()
{
}

CAnimalRoot::~CAnimalRoot()
{
}

HRESULT __stdcall CAnimalRoot::CreateInstance(IN OPTIONAL IUnknown* pUnkOuter, IN REFIID riid, OUT void** ppvObject)
{
    return S_OK;
}

HRESULT __stdcall CAnimalRoot::LockServer(IN BOOL fLock)
{
    return S_OK;
}

HRESULT __stdcall CAnimalRoot::ParseDisplayName(
    IN IBindCtx* pbc, 
    IN LPOLESTR pszDisplayName, 
    OUT ULONG* pchEaten, 
    OUT IMoniker** ppmkOut
)
{
    HRESULT hResult;

    hResult = CreateItemMoniker(OLESTR("!"), pszDisplayName + 1, ppmkOut);
    if (pchEaten)
    {
        if (hResult == S_OK)
        {
            *pchEaten = _tcslen(pszDisplayName);
        }
        else
        {
            *pchEaten = 0;
        }
    }

    return hResult;
}

HRESULT __stdcall CAnimalRoot::EnumObjects(IN DWORD grfFlags, OUT IEnumUnknown** ppenum)
{
    return S_OK;
}

HRESULT __stdcall CAnimalRoot::LockContainer(IN BOOL fLock)
{
    return S_OK;
}

HRESULT __stdcall CAnimalRoot::GetObject(IN LPOLESTR pszItem, IN DWORD dwSpeedNeeded, IN IBindCtx* pbc, IN REFIID riid, OUT void** ppvObject)
{
    IUnknown* lpIUnknown;
    ISetName* lpISetName;

    HRESULT hResult = CoCreateInstance(CLSID_ANIMALS, nullptr, CLSCTX_INPROC_SERVER, riid, ppvObject);
    if (hResult == S_OK)
    {
        lpIUnknown = (IUnknown*)*ppvObject;
        lpIUnknown->QueryInterface(IID_ISetName, (void**)&lpISetName);
        lpISetName->SetName(pszItem);
        lpISetName->Release();
    }
    return hResult;
}

HRESULT __stdcall CAnimalRoot::GetObjectStorage(IN LPOLESTR pszItem, IN IBindCtx* pbc, IN REFIID riid, OUT void** ppvStorage)
{
    return S_OK;
}

HRESULT __stdcall CAnimalRoot::IsRunning(IN LPOLESTR pszItem)
{
    return S_OK;
}
